#include "CAVPlayer.h"
#include "vlc/vlc.h"

#include <cmath>

#define NB_PROFILE \
    (sizeof(video_profile_value_list)/sizeof(video_profile_value_list[0]))

static const char video_profile_name_list[][37] = {
    "Video - H.264 + MP3 (MP4)",
    "Video - VP80 + Vorbis (Webm)",
    "Video - H.264 + MP3 (TS)",
    "Video - H.265 + MP3 (MP4)",
    "Video - Theora + Vorbis (OGG)",
    "Video - MPEG-2 + MPGA (TS)",
    "Video - Dirac + MP3 (TS)",
    "Video - WMV + WMA (ASF)",
    "Video - DIV3 + MP3 (ASF)",
    "Audio - Vorbis (OGG)",
    "Audio - MP3",
    "Audio - FLAC",
    "Audio - CD",
    "Video for MPEG4 720p TV/device",
    "Video for MPEG4 1080p TV/device",
    "Video for DivX compatible player",
    "Video for iPod SD",
    "Video for iPod HD/iPhone/PSP",
    "Video for Android SD Low",
    "Video for Android SD High",
    "Video for Android HD",
    "Video for Youtube SD",
    "Video for Youtube HD",
};

/* !!! Do not add profiles here without widget or muxer alias (see standard.c) support in profile editor !!! */
static const char * video_profile_value_list[] = {
    "audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=0;vcodec_qp=0;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=mp4",
    "video_enable=yes;video_codec=VP80;vcodec_bitrate=2000;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;audio_enable=yes;audio_codec=vorb;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=webm",
    "audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=800;vcodec_qp=0;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=ts",
    "audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=hevc;vcodec_bitrate=0;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=vorb;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=theo;vcodec_bitrate=800;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=ogg",
    "audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=mp2v;vcodec_bitrate=800;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=ts",
    "video_enable=yes;video_codec=drac;vcodec_bitrate=800;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=ts",
    "audio_enable=yes;audio_codec=wma2;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=WMV2;vcodec_bitrate=800;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=asf",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=DIV3;vcodec_bitrate=800;vcodec_framerate=0;vcodec_width=0;vcodec_height=0;muxer_mux=asf",
    "audio_enable=yes;audio_codec=vorb;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=ogg",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=mp3",
    "audio_enable=yes;audio_codec=flac;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=flac",
    "audio_enable=yes;audio_codec=s16l;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=wav",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=192;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=1500;vcodec_qp=0;vcodec_framerate=0;vcodec_width=1280;vcodec_height=720;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=192;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=3500;vcodec_qp=0;vcodec_framerate=0;vcodec_width=1920;vcodec_height=1080;muxer_mux=mp4",
    "video_enable=yes;video_codec=DIV3;vcodec_bitrate=900;vcodec_framerate=0;vcodec_width=720;vcodec_height=576;audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;muxer_mux=avi",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=600;vcodec_qp=0;vcodec_framerate=0;vcodec_width=320;vcodec_height=180;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=700;vcodec_qp=0;vcodec_framerate=0;vcodec_width=480;vcodec_height=272;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=24;acodec_channels=1;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=56;vcodec_qp=0;vcodec_framerate=12;vcodec_width=176;vcodec_height=144;vcodec_custom=profile%3Dbaseline;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=500;vcodec_qp=0;vcodec_framerate=0;vcodec_width=480;vcodec_height=360;vcodec_custom=profile%3Dbaseline;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=192;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=2000;vcodec_qp=0;vcodec_framerate=0;vcodec_width=1280;vcodec_height=720;vcodec_custom=profile%3Dbaseline;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=800;vcodec_qp=0;vcodec_framerate=0;vcodec_width=640;vcodec_height=480;muxer_mux=mp4",
    "audio_enable=yes;audio_codec=mp3;acodec_bitrate=128;acodec_channels=2;acodec_samplerate=44100;video_enable=yes;video_codec=h264;vcodec_bitrate=1500;vcodec_qp=0;vcodec_framerate=0;vcodec_width=1280;vcodec_height=720;muxer_mux=mp4",
};

void OnVLC_Event(const libvlc_event_t *event, void *data);

CAVPlayer::CAVPlayer()
    : m_pVLC_Inst(NULL),
      m_pVLC_Player(NULL),
      m_hWnd(NULL),
      m_pfnPlaying(NULL),
      m_pfnPosChanged(NULL),
      m_pfnEndReached(NULL) {}

CAVPlayer::~CAVPlayer() {
    Release();
}

void CAVPlayer::Init() {
  char *argv[] = {
    {"--intf=dummy"},
    {"--no-media-library"},
    {"--no-stats"},
    {"--no-osd"},
    {"--no-loop"},
    {"--no-video-title-show"},
    {"--drop-late-frames"},
  };

  if (!m_pVLC_Inst) {
    m_pVLC_Inst = libvlc_new(7, argv);
  }
}

void CAVPlayer::Release() {
  Stop();

  if (m_pVLC_Inst) {
    libvlc_release(m_pVLC_Inst);
    m_pVLC_Inst = NULL;
  }
}

bool CAVPlayer::Download(const std::string &strPath) {
  libvlc_instance_t *vlc;

  const char *sout =
      "#transcode{audio_enable=yes;audio_codec=mpga;acodec_bitrate=128;acodec_"
      "channels=2;acodec_samplerate=44100;"
      "video_enable=yes;video_codec=h264}"
      ":file{dst=screen11.mp4,no-overwrite}";

  const char *media_name = "Download";

  const char *url = strPath.c_str();

  vlc = libvlc_new(0, NULL);
  libvlc_vlm_add_broadcast(vlc, media_name, url, sout, 0, NULL, true, false);
  libvlc_vlm_play_media(vlc, media_name);

  // play 30s
  //_sleep(30000);

  // libvlc_vlm_stop_media(vlc, media_name);
  // libvlc_vlm_release(vlc);

  return true;
}

bool CAVPlayer::Play(const std::string &strPath, bool localFile) {
  if (!m_pVLC_Inst) {
    Init();
  }

  if (strPath.empty() || !m_pVLC_Inst) {
    return false;
  }

  Stop();

  bool bRet = false;
  libvlc_media_t *media;

  if (localFile) {
    media = libvlc_media_new_path(m_pVLC_Inst, strPath.c_str());
  } else {
    media = libvlc_media_new_location(m_pVLC_Inst, strPath.c_str());
  }

  if (media) {
    m_pVLC_Player = libvlc_media_player_new_from_media(media);
    if (m_pVLC_Player) {
      // libvlc_media_player_set_xwindow
      libvlc_media_player_set_hwnd(m_pVLC_Player, m_hWnd);
      libvlc_media_player_play(m_pVLC_Player);

      // 事件管理
      libvlc_event_manager_t *vlc_evt_man =
          libvlc_media_player_event_manager(m_pVLC_Player);
      libvlc_event_attach(vlc_evt_man, libvlc_MediaStateChanged, ::OnVLC_Event,
                          this);
      libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerPlaying, ::OnVLC_Event,
                          this);
      libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerPositionChanged,
                          ::OnVLC_Event, this);
      libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerEndReached,
                          ::OnVLC_Event, this);
      bRet = true;
    }

    libvlc_media_release(media);
  }

  return bRet;
}

void CAVPlayer::Stop() {
  if (m_pVLC_Player) {
    libvlc_media_player_stop(m_pVLC_Player);    /* Stop playing */
    libvlc_media_player_release(m_pVLC_Player); /* Free the media_player */
    m_pVLC_Player = NULL;
  }
}

void CAVPlayer::Play() {
  if (m_pVLC_Player) {
    libvlc_media_player_play(m_pVLC_Player);
  }
}

void CAVPlayer::Pause() {
  if (m_pVLC_Player) {
    libvlc_media_player_pause(m_pVLC_Player);
  }
}

void CAVPlayer::Volume(int iVol) {
  if (iVol < 0) {
    return;
  }

  if (m_pVLC_Player) {
    libvlc_audio_set_volume(
        m_pVLC_Player,
        int(iVol *
            1.3));  // 如果放到100，感觉比迅雷的100少了30，所以这里用1.3倍音量
  }
}

void CAVPlayer::VolumeIncrease() {
  if (m_pVLC_Player) {
    int iVol = libvlc_audio_get_volume(m_pVLC_Player);
    Volume((int)ceil(iVol * 1.1));
  }
}

void CAVPlayer::VolumeReduce() {
  if (m_pVLC_Player) {
    int iVol = libvlc_audio_get_volume(m_pVLC_Player);
    Volume((int)floor(iVol * 0.9));
  }
}

int CAVPlayer::GetPos() {
  if (m_pVLC_Player) {
    return (int)(1000 * libvlc_media_player_get_position(m_pVLC_Player));
  }

  return 0;
}

void CAVPlayer::SeekTo(int iPos) {
  if (iPos < 0 || iPos > 1000) {
    return;
  }

  if (m_pVLC_Player) {
    libvlc_media_player_set_position(m_pVLC_Player, iPos / (float)1000.0);
  }
}

void CAVPlayer::SeekForward() {
  // int iPos = GetPos();
  // SeekTo((int)ceil(iPos * 1.1));

  // 一次快退5秒
  if (m_pVLC_Player) {
    libvlc_time_t i_time = libvlc_media_player_get_time(m_pVLC_Player) + 5000;

    if (i_time > GetTotalTime()) {
      i_time = GetTotalTime();
    }

    libvlc_media_player_set_time(m_pVLC_Player, i_time);
  }
}

void CAVPlayer::SeekBackward() {
  // int iPos = GetPos();
  // SeekTo((int)floor(iPos * 0.9));

  if (m_pVLC_Player) {
    libvlc_time_t i_time = libvlc_media_player_get_time(m_pVLC_Player) - 5000;

    if (i_time < 0) {
      i_time = 0;
    }

    libvlc_media_player_set_time(m_pVLC_Player, i_time);
  }
}

void CAVPlayer::SetHWND(HWND hwnd) {
  if (::IsWindow(hwnd)) {
    m_hWnd = hwnd;
  }
}

HWND CAVPlayer::GetHWND() { return m_hWnd; }

void CAVPlayer::SetFullScreen(bool full) {
  libvlc_set_fullscreen(m_pVLC_Player, full);
  int iRet = libvlc_get_fullscreen(m_pVLC_Player);
}

bool CAVPlayer::IsOpen() { return NULL != m_pVLC_Player; }

bool CAVPlayer::IsPlaying() {
  if (m_pVLC_Player) {
    return (1 == libvlc_media_player_is_playing(m_pVLC_Player));
  }

  return false;
}

__int64 CAVPlayer::GetTotalTime() {
  if (m_pVLC_Player) {
    return libvlc_media_player_get_length(m_pVLC_Player);
  }

  return 0;
}

__int64 CAVPlayer::GetTime() {
  if (m_pVLC_Player) {
    return libvlc_media_player_get_time(m_pVLC_Player);
  }

  return 0;
}

int CAVPlayer::GetVolume() {
  if (m_pVLC_Player) {
    return libvlc_audio_get_volume(m_pVLC_Player);
  }

  return 0;
}

void CAVPlayer::SetCallbackStateChanged(pfnCallback pfn) {
  m_pfnStateChanged = pfn;
}

void CAVPlayer::SetCallbackPlaying(pfnCallback pfn) { m_pfnPlaying = pfn; }

void CAVPlayer::SetCallbackPosChanged(pfnCallback pfn) {
  m_pfnPosChanged = pfn;
}

void CAVPlayer::SetCallbackEndReached(pfnCallback pfn) {
  m_pfnEndReached = pfn;
}

void OnVLC_Event(const libvlc_event_t *event, void *data) {
  CAVPlayer *pAVPlayer = (CAVPlayer *)data;
  pfnCallback pfn = NULL;

  if (!pAVPlayer) {
    return;
  }

  switch (event->type) {
    case libvlc_MediaStateChanged:
      pfn = pAVPlayer->m_pfnStateChanged;
      break;
    case libvlc_MediaPlayerPlaying:
      pfn = pAVPlayer->m_pfnPlaying;
      break;
    case libvlc_MediaPlayerPositionChanged:
      pfn = pAVPlayer->m_pfnPosChanged;
      break;
    case libvlc_MediaPlayerEndReached:
      pfn = pAVPlayer->m_pfnEndReached;
      break;
    default:
      break;
  }

  if (pfn) {
    pfn(data);
  }
}
